use std::collections::HashMap;
use bincode::{Decode, Encode};
use bytes::{Buf, BufMut, BytesMut};
use log::info;
use rpc::router::{DoRouter, RouterFactory};
use rpc::{encode, DefaultLocalSeqCreator, RpcContext, RpcResult};
use rpc_derive::{router, rpc_router};
use rpc_server::server::RpcServerBuilder;
use serde::{Deserialize, Serialize};
use rpc::bootstrap::BootstrapBuilder;
use rpc::codec::RpcEncode;

pub struct ReceiveMessageRouterFactory;

pub struct ReceiveMessageRouter {
    pub message_object: MessageObject,
}

#[derive(Debug, Clone, Deserialize, Serialize, Encode, Decode, PartialEq)]
pub struct MessageObject {
    pub content: String,
}

// impl RpcDecode<MessageObject> for MessageObject {
//     fn decode(buf: &mut BytesMut) -> Result<MessageObject, RpcError> {
//         Ok(MessageObject { content: String::from_utf8(buf.to_vec()).unwrap() })
//     }
// }

#[derive(Debug, Clone, Deserialize, Serialize, Encode, Decode)]
pub struct OkResp {

}

// impl RpcEncode for OkResp {
//     fn encode(&self, context: &RpcContext) -> RpcResult<Vec<u8>> {
//         encode(context, self)
//     }
// }

// impl RpcEncode for OkResp {
//     fn encode(&self, buf: &mut BytesMut) -> Result<(), RpcError> {
//         Ok(())
//     }
// }

impl RouterFactory for ReceiveMessageRouterFactory {
    fn parse(&self, context: &RpcContext, bytes_mut: BytesMut) -> RpcResult<Box<dyn DoRouter>> {
        let tt = ReceiveMessageRouter {
            message_object: MessageObject { content: String::from_utf8(bytes_mut.to_vec()).unwrap() },
        };
        Ok(Box::new(tt))
    }
}

impl DoRouter for ReceiveMessageRouter {

    fn execute(&mut self, map: &mut RpcContext) -> RpcResult<Box<dyn RpcEncode>> {
        info!("Receive message router");
        // if let Some(int_val) = map.get_data("t1").and_then(|b| b.downcast_ref::<&str>()) {
        //     info!("str: {}", int_val);
        // }
        //
        // if let Some(int_val) = map.get_data("t2").and_then(|b| b.downcast_ref::<i32>()) {
        //     info!("int: {}", int_val);
        // }
        //
        // if let Some(int_val) = map.get_data("t3").and_then(|b| b.downcast_ref::<String>()) {
        //     info!("String: {}", int_val);
        // }

        Ok(Box::new(OkResp {}))
    }
}

pub struct ReaderMessagesRouterFactory;

pub struct ReaderMessagesRouter {

}

pub struct OtherOkResp {

}

// impl RpcEncode for OtherOkResp {
//     fn encode(&self, buf: &mut BytesMut) -> Result<(), RpcError> {
//         Ok(())
//     }
// }

impl RouterFactory for ReaderMessagesRouterFactory {
    fn parse(&self, context: &RpcContext, decode: BytesMut) -> RpcResult<Box<dyn DoRouter>> {
        let mut session = context.session();
        session.add_data("t1".to_string(), Box::new("hello".to_string()));
        let result = session.with_data::<String, i32>("t1", |b| {
            info!("t1 value: {}", b);
            12
        });
        assert_eq!(true, result.is_some());
        Ok(Box::new(ReaderMessagesRouter {}))
    }
}

impl DoRouter for ReaderMessagesRouter {

    fn execute(&mut self, mut context: &mut RpcContext) -> RpcResult<Box<dyn RpcEncode>>  {
        let mut session = context.session();
        info!("reader message router");
        let result = session.with_data::<String, i32>("t1", |b| {
            info!("t1 value: {}", b);
            12
        });
        assert_eq!(true, result.is_some());
        // if let Some(int_val) = map.get_data("t1").and_then(|b| b.downcast_ref::<&str>()) {
        //     info!("str: {}", int_val);
        // }
        //
        // if let Some(int_val) = map.get_data("t2").and_then(|b| b.downcast_ref::<i32>()) {
        //     info!("int: {}", int_val);
        // }
        //
        // if let Some(int_val) = map.get_data("t3").and_then(|b| b.downcast_ref::<String>()) {
        //     info!("String: {}", int_val);
        // }
        // Ok(Box::new(OtherOkResp {}))
        Ok(Box::new(result))
    }
}

#[rpc_router]
fn demo(_context: &mut RpcContext, _message_object: MessageObject) -> OkResp {
    info!("demo  ----------------------");
    OkResp {

    }
}

// pub struct DemoRouterFactory;
// #[derive(Debug)]
// pub struct DemoRouter {
//     pub message_object: MessageObject,
// }
// impl rpc::router::RouterFactory for DemoRouterFactory {
//     fn parse(&self, rpc_context: &dyn rpc::RpcContext, byte_muts: bytes::BytesMut) -> rpc::RpcResult<Box<dyn rpc::router::DoRouter>> {
//         Ok(Box::new(DemoRouter {
//             message_object: {
//                 let mut decode = get_current_rpc_decode::<MessageObject>(rpc_context, byte_muts.freeze().to_vec())?;
//                 let value = decode.decode()?;
//                 value
//             },
//         }))
//     }
// }
// impl rpc::router::DoRouter for DemoRouter {
//     fn execute(&mut self, mut rpc_context: &mut dyn rpc::RpcContext) -> Result<Vec<u8>, rpc::error::RpcError> {
//         let result = demo(rpc_context, self.message_object.clone());
//         rpc::encode(rpc_context, result)
//     }
// }


#[rpc_router]
fn demo2(_data: MessageObject) -> OkResp {
    info!("demo  ----------------------");
    OkResp {

    }
}

// pub struct Demo2RouterFactory;
// pub struct Demo2Router {
//     pub message_object: MessageObject,
// }
// impl rpc::router::RouterFactory for Demo2RouterFactory {
//     fn parse(&self, byte_muts: bytes::BytesMut) -> Box<dyn rpc::router::DoRouter> {
//         let mut new_bytes_mut = byte_muts;
//         use rpc::codec::RpcDecode;
//         Box::new(Demo2Router {
//             message_object: MessageObject::decode(&mut new_bytes_mut).unwrap(),
//         })
//     }
// }
// impl rpc::router::DoRouter for Demo2Router {
//     fn execute(
//         &mut self,
//         mut rpc_context: &mut dyn rpc::RpcContext,
//     ) -> Result<Box<dyn rpc::codec::RpcEncode>, rpc::error::RpcError> {
//         let result = demo2(self.message_object.clone());
//     }
// }


#[test]
fn router_test0()->RpcResult<()> {
    let mut rpc_context = RpcContext::test_context_with_codec_type("json");
    let router_factory = ReaderMessagesRouterFactory {};
    let bytes_mut = BytesMut::new();
    let mut router = router_factory.parse(&rpc_context, bytes_mut)?;
    router.execute(&mut rpc_context).unwrap();
    let _t = rpc_context;
    Ok(())
}

#[test]
fn router_test10()->RpcResult<()> {
    let mut rpc_context = RpcContext::test_context_with_codec_type("json");
    let router_factory = router!(demo);
    let message_object = MessageObject {content: "hello".to_string()};
    let bytes = encode(&rpc_context, &message_object)?;
    let mut bytes_mut = BytesMut::from(&bytes[..]);
    let mut router = router_factory.parse(&rpc_context, bytes_mut)?;
    router.execute(&mut rpc_context).unwrap();
    let t = rpc_context;
    Ok(())
}

#[test]
fn router_test()->RpcResult<()> {
    let mut router_map : HashMap<&str, Box<dyn RouterFactory>> = HashMap::new();

    router_map.insert("receiveMessage", Box::new(ReceiveMessageRouterFactory));
    router_map.insert("readMessage", Box::new(ReaderMessagesRouterFactory));

    let router = router_map.get("receiveMessage").unwrap();
    let mut rpc_context = RpcContext::test_context_with_codec_type("json");

    let message_object = MessageObject {content: "hello".to_string()};
    let mut bytes = encode(&rpc_context, &message_object)?;
    let mut new_router = router.parse(&rpc_context, BytesMut::from(&bytes[..]))?;
    let resp = new_router.execute(&mut rpc_context);

    let bootstrap = BootstrapBuilder::new()
        .router("/demo", router!(demo))
        .router("/demo2", router!(demo2))
        ;
    let rpc_server = RpcServerBuilder::new(bootstrap, 8899)
        .build();

    let router_factory = rpc_server.get_router("/demo").unwrap();
    let mut rpc_context = RpcContext::test_context_with_codec_type("json");
    let mut router = router_factory.parse(&rpc_context, BytesMut::from(&bytes[..]))?;
    let result = router.execute(&mut rpc_context)?;
    Ok(())
}

#[test]
fn bytemut_test() {
    let bytes_mut = BytesMut::new();
    decode_test(bytes_mut);

}

fn decode_test(bytes_mut2: BytesMut) {
    let mut bytes_mut = bytes_mut2;
    bytes_mut.put_i32(1);
    bytes_mut.put_i32(2);
    bytes_mut.put_i32(3);

    info!("{}", bytes_mut.get_i32());
    info!("{}", bytes_mut.get_i32());
    info!("{}", bytes_mut.get_i32());
}

fn decode(bytes_mut: &mut BytesMut)->i32 {
    bytes_mut.get_i32()
}